"""
插件注册表

管理插件的注册、查找和元数据。
"""

from typing import Dict, List, Optional, Set, Type
import threading
from pathlib import Path

from .base import Plugin, PluginMetadata, PluginState
from .exceptions import PluginRegistryError, PluginConflictError


class PluginRegistry:
    """
    插件注册表
    
    管理所有已注册插件的信息和状态。
    """
    
    def __init__(self):
        self._plugins: Dict[str, Plugin] = {}
        self._metadata: Dict[str, PluginMetadata] = {}
        self._plugin_classes: Dict[str, Type[Plugin]] = {}
        self._dependencies: Dict[str, Set[str]] = {}
        self._dependents: Dict[str, Set[str]] = {}
        self._categories: Dict[str, Set[str]] = {}
        self._tags: Dict[str, Set[str]] = {}
        self._lock = threading.RLock()
    
    def register(self, plugin: Plugin, metadata: Optional[PluginMetadata] = None) -> None:
        """
        注册插件
        
        Args:
            plugin: 插件实例
            metadata: 插件元数据
        
        Raises:
            PluginConflictError: 插件名称冲突
            PluginRegistryError: 注册失败
        """
        with self._lock:
            plugin_name = plugin.name
            
            # 检查名称冲突
            if plugin_name in self._plugins:
                existing_plugin = self._plugins[plugin_name]
                if existing_plugin.version != plugin.version:
                    raise PluginConflictError(
                        f"插件名称冲突: {plugin_name} (已存在版本: {existing_plugin.version}, 新版本: {plugin.version})",
                        plugin_name=plugin_name,
                        conflicting_plugin=existing_plugin.name
                    )
                else:
                    # 相同版本，直接返回
                    return
            
            # 使用插件自带的元数据或提供的元数据
            if metadata is None:
                metadata = plugin.metadata
            
            if metadata is None:
                # 创建默认元数据
                metadata = PluginMetadata(
                    name=plugin.name,
                    version=plugin.version,
                    description=plugin.description,
                    author=plugin.author,
                    dependencies=plugin.dependencies
                )
            
            # 检查依赖冲突
            self._check_conflicts(plugin_name, metadata)
            
            # 注册插件
            self._plugins[plugin_name] = plugin
            self._metadata[plugin_name] = metadata
            self._plugin_classes[plugin_name] = plugin.__class__
            
            # 更新依赖关系
            self._update_dependencies(plugin_name, metadata)
            
            # 更新分类和标签
            self._update_categories_and_tags(plugin_name, metadata)
            
            # 设置插件状态
            plugin.set_state(PluginState.LOADED)
            plugin.metadata = metadata
    
    def unregister(self, plugin_name: str) -> bool:
        """
        注销插件
        
        Args:
            plugin_name: 插件名称
        
        Returns:
            是否成功注销
        """
        with self._lock:
            if plugin_name not in self._plugins:
                return False
            
            # 检查是否有其他插件依赖此插件
            dependents = self._dependents.get(plugin_name, set())
            if dependents:
                active_dependents = []
                for dependent in dependents:
                    if (dependent in self._plugins and 
                        self._plugins[dependent].is_active()):
                        active_dependents.append(dependent)
                
                if active_dependents:
                    raise PluginRegistryError(
                        f"无法注销插件 {plugin_name}，以下插件依赖它: {', '.join(active_dependents)}"
                    )
            
            # 获取插件和元数据
            plugin = self._plugins[plugin_name]
            metadata = self._metadata[plugin_name]
            
            # 清理依赖关系
            self._cleanup_dependencies(plugin_name, metadata)
            
            # 清理分类和标签
            self._cleanup_categories_and_tags(plugin_name, metadata)
            
            # 移除插件
            del self._plugins[plugin_name]
            del self._metadata[plugin_name]
            del self._plugin_classes[plugin_name]
            
            # 设置插件状态
            plugin.set_state(PluginState.DESTROYED)
            
            return True
    
    def get_plugin(self, plugin_name: str) -> Optional[Plugin]:
        """获取插件实例"""
        return self._plugins.get(plugin_name)
    
    def get_metadata(self, plugin_name: str) -> Optional[PluginMetadata]:
        """获取插件元数据"""
        return self._metadata.get(plugin_name)
    
    def get_plugin_class(self, plugin_name: str) -> Optional[Type[Plugin]]:
        """获取插件类"""
        return self._plugin_classes.get(plugin_name)
    
    def has_plugin(self, plugin_name: str) -> bool:
        """检查插件是否已注册"""
        return plugin_name in self._plugins
    
    def list_plugins(self, 
                    category: Optional[str] = None,
                    tag: Optional[str] = None,
                    state: Optional[PluginState] = None) -> List[str]:
        """
        列出插件
        
        Args:
            category: 按分类过滤
            tag: 按标签过滤
            state: 按状态过滤
        
        Returns:
            插件名称列表
        """
        with self._lock:
            plugins = list(self._plugins.keys())
            
            # 按分类过滤
            if category:
                if category in self._categories:
                    plugins = [p for p in plugins if p in self._categories[category]]
                else:
                    plugins = []
            
            # 按标签过滤
            if tag:
                if tag in self._tags:
                    plugins = [p for p in plugins if p in self._tags[tag]]
                else:
                    plugins = []
            
            # 按状态过滤
            if state:
                plugins = [p for p in plugins if self._plugins[p].state == state]
            
            return plugins
    
    def get_dependencies(self, plugin_name: str) -> Set[str]:
        """获取插件依赖"""
        return self._dependencies.get(plugin_name, set()).copy()
    
    def get_dependents(self, plugin_name: str) -> Set[str]:
        """获取依赖此插件的插件"""
        return self._dependents.get(plugin_name, set()).copy()
    
    def get_categories(self) -> List[str]:
        """获取所有分类"""
        return list(self._categories.keys())
    
    def get_tags(self) -> List[str]:
        """获取所有标签"""
        return list(self._tags.keys())
    
    def get_plugins_by_category(self, category: str) -> List[str]:
        """按分类获取插件"""
        return list(self._categories.get(category, set()))
    
    def get_plugins_by_tag(self, tag: str) -> List[str]:
        """按标签获取插件"""
        return list(self._tags.get(tag, set()))
    
    def check_dependencies(self, plugin_name: str) -> Dict[str, bool]:
        """
        检查插件依赖是否满足
        
        Returns:
            依赖检查结果，键为依赖名称，值为是否满足
        """
        if plugin_name not in self._metadata:
            return {}
        
        metadata = self._metadata[plugin_name]
        result = {}
        
        for dependency in metadata.dependencies:
            result[dependency] = self.has_plugin(dependency)
        
        return result
    
    def get_load_order(self, plugin_names: Optional[List[str]] = None) -> List[str]:
        """
        获取插件加载顺序（拓扑排序）
        
        Args:
            plugin_names: 要排序的插件列表，None表示所有插件
        
        Returns:
            按依赖关系排序的插件列表
        """
        if plugin_names is None:
            plugin_names = list(self._plugins.keys())
        
        # 拓扑排序
        visited = set()
        temp_visited = set()
        result = []
        
        def visit(plugin_name: str):
            if plugin_name in temp_visited:
                raise PluginRegistryError(f"检测到循环依赖: {plugin_name}")
            
            if plugin_name in visited:
                return
            
            temp_visited.add(plugin_name)
            
            # 访问依赖
            dependencies = self._dependencies.get(plugin_name, set())
            for dependency in dependencies:
                if dependency in plugin_names:
                    visit(dependency)
            
            temp_visited.remove(plugin_name)
            visited.add(plugin_name)
            result.append(plugin_name)
        
        for plugin_name in plugin_names:
            if plugin_name not in visited:
                visit(plugin_name)
        
        return result
    
    def _check_conflicts(self, plugin_name: str, metadata: PluginMetadata) -> None:
        """检查插件冲突"""
        for conflict in metadata.conflicts:
            if conflict in self._plugins:
                raise PluginConflictError(
                    f"插件 {plugin_name} 与已注册插件 {conflict} 冲突",
                    plugin_name=plugin_name,
                    conflicting_plugin=conflict
                )
    
    def _update_dependencies(self, plugin_name: str, metadata: PluginMetadata) -> None:
        """更新依赖关系"""
        # 更新此插件的依赖
        dependencies = set(metadata.dependencies)
        self._dependencies[plugin_name] = dependencies
        
        # 更新被依赖关系
        for dependency in dependencies:
            if dependency not in self._dependents:
                self._dependents[dependency] = set()
            self._dependents[dependency].add(plugin_name)
    
    def _cleanup_dependencies(self, plugin_name: str, metadata: PluginMetadata) -> None:
        """清理依赖关系"""
        # 清理此插件的依赖
        if plugin_name in self._dependencies:
            dependencies = self._dependencies[plugin_name]
            for dependency in dependencies:
                if dependency in self._dependents:
                    self._dependents[dependency].discard(plugin_name)
                    if not self._dependents[dependency]:
                        del self._dependents[dependency]
            del self._dependencies[plugin_name]
    
    def _update_categories_and_tags(self, plugin_name: str, metadata: PluginMetadata) -> None:
        """更新分类和标签"""
        # 更新分类
        if metadata.category:
            if metadata.category not in self._categories:
                self._categories[metadata.category] = set()
            self._categories[metadata.category].add(plugin_name)
        
        # 更新标签
        for tag in metadata.tags:
            if tag not in self._tags:
                self._tags[tag] = set()
            self._tags[tag].add(plugin_name)
    
    def _cleanup_categories_and_tags(self, plugin_name: str, metadata: PluginMetadata) -> None:
        """清理分类和标签"""
        # 清理分类
        if metadata.category and metadata.category in self._categories:
            self._categories[metadata.category].discard(plugin_name)
            if not self._categories[metadata.category]:
                del self._categories[metadata.category]
        
        # 清理标签
        for tag in metadata.tags:
            if tag in self._tags:
                self._tags[tag].discard(plugin_name)
                if not self._tags[tag]:
                    del self._tags[tag]
    
    def get_statistics(self) -> Dict[str, any]:
        """获取注册表统计信息"""
        with self._lock:
            state_counts = {}
            for plugin in self._plugins.values():
                state = plugin.state.value
                state_counts[state] = state_counts.get(state, 0) + 1
            
            return {
                "total_plugins": len(self._plugins),
                "categories": len(self._categories),
                "tags": len(self._tags),
                "state_distribution": state_counts,
                "dependency_count": sum(len(deps) for deps in self._dependencies.values()),
            }
    
    def clear(self) -> None:
        """清空注册表"""
        with self._lock:
            # 设置所有插件状态为已销毁
            for plugin in self._plugins.values():
                plugin.set_state(PluginState.DESTROYED)
            
            self._plugins.clear()
            self._metadata.clear()
            self._plugin_classes.clear()
            self._dependencies.clear()
            self._dependents.clear()
            self._categories.clear()
            self._tags.clear()


# 全局插件注册表
plugin_registry = PluginRegistry()
